package com.millstein.mq;

import com.millstein.model.CouponRecordMessage;
import com.millstein.service.CouponTaskService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @description:
 * @author: tsing
 * @create: 2021-09-20 20:49
 */
@Slf4j
@Component
@RabbitListener(queues = "${mqconfig.coupon-release-queue}")
public class CouponReleaseListener {

    @Autowired
    private CouponTaskService couponTaskService;

    @RabbitHandler
    public void handleCouponRecordMessage(CouponRecordMessage couponRecordMessage, Message message, Channel channel) {
        log.info("收到了优惠券解锁的消息，内容是：{}", couponRecordMessage);

        // 1.获取消息投递的标识，用来进行手动确认
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            // 2.解锁优惠券，返回是否需要重新投递的标识
            boolean retry = couponTaskService.doReleaseCouponRecord(couponRecordMessage);

            // 3.根据是否需要重新投递分别执行（retry为true时重新投递，false时直接确认）
            doAfterReleaseByRetry(channel, deliveryTag, retry, couponRecordMessage);

        } catch (Exception e) {

            // 4.如果发生异常，那么也要进行后续处理（重新投递）
            doAfterReleaseWhileOccurredException(channel, deliveryTag, e, couponRecordMessage);
        }
    }

    /**
     * 根据是否需要重新投递分别执行。当retry为true时进行重新投递，为false时手动确认消息
     * @param channel 消息的通道
     * @param deliveryTag 消息投递的标识
     * @param retry 是否需要重新投递
     * @param couponRecordMessage 消息的内容
     */
    private void doAfterReleaseByRetry(Channel channel,
                                       long deliveryTag,
                                       boolean retry,
                                       CouponRecordMessage couponRecordMessage) {
        try {
            if (retry) {
                log.error("优惠券解锁失败，需要重新投递：{}", couponRecordMessage);
                channel.basicReject(deliveryTag, true);
            } else {
                log.info("优惠券解锁成功：{}", couponRecordMessage);
                channel.basicAck(deliveryTag, false);
            }
        } catch (Exception e) {
            // TODO 这里可以直接写入数据库，等待人工核查
            log.error("后续处理失败：{}，原因是：{}", couponRecordMessage, e.getMessage(), e);
        }
    }

    /**
     * 在释放优惠券的过程中如果发生异常，那么也要重新投递
     * @param channel 消息的通道
     * @param deliveryTag 消息投递的标识
     * @param e 异常对象
     * @param couponRecordMessage 消息的内容
     */
    private void doAfterReleaseWhileOccurredException(Channel channel,
                                                      long deliveryTag,
                                                      Exception e,
                                                      CouponRecordMessage couponRecordMessage) {
        try {
            log.error("解锁优惠券时发生了异常：{}，消息内容是：{}", e.getMessage(), couponRecordMessage, e);
            channel.basicReject(deliveryTag, true);
        } catch (Exception ex) {
            // TODO 这里可以直接写入数据库，等待人工核查
            log.error("异常处理失败：{}，原因是：{}", couponRecordMessage, ex.getMessage(), ex);
        }

    }

    @RabbitHandler
    public void handleNormalMessage(String normalMessage, Message message, Channel channel) {
        log.info("收到了普通的消息，内容是：{}", normalMessage);
    }
}
